package com.dtb.trade.service;

import com.alibaba.fastjson.JSON;
import com.dtb.trade.dao.mongodb.second.SecondRepository;
import com.dtb.trade.entity.PointDeal;
import com.dtb.trade.entity.mongodb.second.SecondBlock;
import com.dtb.trade.util.BlockConstant;
import com.dtb.trade.util.EncryptUtil;
import com.dtb.trade.util.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author:ChengJian
 * @Description:
 * @Date: Created in 上午11:26 2018/8/21
 */
@Service(value = "secondBlockService")
public class SecondBlockService implements BaseService<SecondBlock> {

    @Autowired
    SecondRepository secondRepository;

    @Autowired
    RedisService redisService;


    @Override
    public void addBlock(SecondBlock secondBlock) {
       secondRepository.save(secondBlock);
    }

    @Override
    public SecondBlock getNewest() {
        long count = secondRepository.count();
        if (count == 0){
            return null;
        }
        return secondRepository.findBlockByIndex(count);
    }

    @Override
    public SecondBlock getBlockByIndex(int index) {
        return secondRepository.findBlockByIndex(index);
    }

    @Override
    public boolean hyperledger(SecondBlock block, List<PointDeal> pointDeals) {

        int blockNum = BlockConstant.blockNum;

        int blockMax = BlockConstant.blockMax;


        if (block != null && block.getPointDeals() != null){
            blockNum   = block.getPointDeals().size();
        }

        //准备记账的记忆记录个数
        int recordNum  = pointDeals.size();

        //欠缺，补足到最大区块个数
        int deficiency = blockMax - blockNum;

        //该区块是否能满足记账交易记录的个数，0刚好满足，正数绰绰有余，负数不满足，生成新的区块
        int surplusNum = deficiency-recordNum;

        if (blockNum < blockMax){
            //更新区块信息
            if (surplusNum >= 0){
                block.getPointDeals().addAll(pointDeals);
                block.setData(JSON.toJSONString(block.getPointDeals()));
                secondRepository.save(block);
            }else {
                //填补区块剩余
                for (int j =0;j<deficiency;j++){
                    block.getPointDeals().add(pointDeals.get(0));
                    pointDeals.remove(0);
                    //更新到数据库
                    block.setData(JSON.toJSONString(block.getPointDeals()));
                    secondRepository.save(block);
                    redisService.set("blockIndexSecond",block.getIndex()+"");
                }
                //生成下一区块
                String nextPrev = block.getHash();
                int nextIndex   = block.getIndex()+1;
                int nextnonce   = block.getNonce();
                long nextTime   = System.currentTimeMillis();
                String nextHash = EncryptUtil.Encrypt(nextPrev+nextIndex+nextnonce+nextTime+block.getData());

                SecondBlock nextBlock = new SecondBlock();
                nextBlock.setTimestamp(nextTime);
                nextBlock.setPreviousHash(nextPrev);
                nextBlock.setHash(nextHash);
                nextBlock.setNonce(nextnonce);
                nextBlock.setIndex(nextIndex);
                tally(nextBlock,pointDeals);
            }
        }else {
            //直接生成新区块
            String nextPrev      = block.getHash();
            int nextIndex        = block.getIndex()+1;
            int nextnonce        = block.getNonce();
            long nextTime        = System.currentTimeMillis();
            String nextHash      = EncryptUtil.Encrypt(nextPrev+nextIndex+nextnonce+nextTime+block.getData());
            List<PointDeal> list = new ArrayList<>();

            SecondBlock nextBlock = new SecondBlock();
            nextBlock.setTimestamp(nextTime);
            nextBlock.setPreviousHash(nextPrev);
            nextBlock.setHash(nextHash);
            nextBlock.setNonce(nextnonce);
            nextBlock.setIndex(nextIndex);
            nextBlock.setPointDeals(list);
            tally(nextBlock,pointDeals);

        }

        return true;
    }

    @Override
    public void tally(SecondBlock block, List<PointDeal> pointDeals) {

        int recordNum  = pointDeals.size();
        int deficiency = BlockConstant.blockMax - BlockConstant.blockNum;
        int surplusNum = deficiency-recordNum;

        if (surplusNum >= 0){
            //满足
            block.getPointDeals().addAll(pointDeals);
            block.setData(JSON.toJSONString(block.getPointDeals()));
            secondRepository.insert(block);
            redisService.set("blockIndexSecond",block.getIndex()+"");
        }else {
            //不满足
            for (int j =0;j<deficiency;j++){
                block.getPointDeals().add(pointDeals.get(0));
                pointDeals.remove(0);
            }
            block.setData(JSON.toJSONString(block.getPointDeals()));
            //更新到数据库
            secondRepository.insert(block);

            //生成下一区块
            String nextPrev      = block.getHash();
            int nextIndex        = block.getIndex()+1;
            int nextnonce        = block.getNonce();
            long nextTime        = System.currentTimeMillis();
            String nextHash      = EncryptUtil.Encrypt(nextPrev+nextIndex+nextnonce+nextTime+block.getData());
            List<PointDeal> list = new ArrayList<>();

            SecondBlock nextBlock = new SecondBlock();
            nextBlock.setTimestamp(nextTime);
            nextBlock.setPreviousHash(nextPrev);
            nextBlock.setHash(nextHash);
            nextBlock.setNonce(nextnonce);
            nextBlock.setIndex(nextIndex);
            nextBlock.setPointDeals(list);

            tally(nextBlock,pointDeals);
        }
    }

    @Override
    public void deleteAllBlock() {
        secondRepository.deleteAll();
    }

    @Override
    public boolean prove() {
        List<SecondBlock> list = secondRepository.findAll();
        // 首先判断创世区块是否被篡改
        SecondBlock first = list.get(0);
        String hash      = EncryptUtil.Encrypt(first.getPreviousHash()+first.getIndex()+first.getNonce()+first.getTimestamp());

        if (!hash.equals(first.getHash())){
            return false;
        }

        for (int i =0;i<list.size()-1;i++){

            SecondBlock pre = list.get(i);

            String preHash  = pre.getHash();
            int nextIndex   = pre.getIndex()+1;
            int nextnonce   = pre.getNonce();
            long nextTime   = list.get(i+1).getTimestamp();
            String nextHash = EncryptUtil.Encrypt(preHash+nextIndex+nextnonce+nextTime+pre.getData());

            if (!nextHash.equals(list.get(i+1).getHash())){
                return false;
            }
        }

        return true;
    }

    @Override
    public List<SecondBlock> getCurrentBlocks(int index) {
        return secondRepository.findSecondBlockByIndex(index);
    }

    @Override
    public boolean isHaveBlock() {
        List<SecondBlock> list = secondRepository.findAll();
        if (list != null && list.size() >0){
            return true;
        }
        return false;
    }



}
